<?php

namespace app\admin\controller;

use app\common\controller\Backend;
use think\Exception;
use think\Cache;

/**
 * AI功能控制器
 */
class Ai extends Backend
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $layout = '';

    /**
     * AI配置
     */
    private $aiConfig;

    public function _initialize()
    {
        // 跳过父类初始化以避免权限检查
        // parent::_initialize();

        // 加载AI配置（静默处理）
        try {
            $this->aiConfig = null;

            // 方法1: 使用config助手函数
            if (function_exists('config')) {
                $this->aiConfig = config('ai');
            }

            // 方法2: 使用Config类
            if (empty($this->aiConfig) && class_exists('\\think\\Config')) {
                $this->aiConfig = \think\Config::get('ai');
            }

            // 方法3: 直接包含配置文件
            if (empty($this->aiConfig)) {
                $configFile = APP_PATH . 'extra/ai.php';
                if (file_exists($configFile)) {
                    $this->aiConfig = include $configFile;
                }
            }
        } catch (\Exception $e) {
            // 静默处理初始化错误
            $this->aiConfig = [];
        }
    }

    /**
     * 记录日志的简单方法
     */
    private function writeLog($message, $type = 'info')
    {
        try {
            $logFile = $_SERVER["DOCUMENT_ROOT"] . "/../runtime/ai.log";
            $time = date('Y-m-d H:i:s');
            $content = "[{$time}] [{$type}] {$message}\n";
            
            // 确保目录存在
            $logDir = dirname($logFile);
            if (!is_dir($logDir)) {
                @mkdir($logDir, 0755, true);
            }
            
            @file_put_contents($logFile, $content, FILE_APPEND | LOCK_EX);
        } catch (\Exception $e) {
            // 日志写入失败时不抛出异常，避免影响主要功能
        }
    }

    /**
     * AI文本生成
     */
    public function generateText()
    {
        if (!$this->request->isPost()) {
            return json(['code' => 0, 'msg' => '请求方式错误']);
        }

        // 检查AI配置是否加载成功
        if (!is_array($this->aiConfig) || empty($this->aiConfig)) {
            $this->writeLog("AI配置检查失败", 'error');
            return json(['code' => 0, 'msg' => 'AI配置未找到或格式错误']);
        }

        $prompt = $this->request->post('prompt', '');
        $type = $this->request->post('type', 'general');
        $maxTokens = $this->request->post('max_tokens', 1000);
        $temperature = $this->request->post('temperature', 0.7);
        $provider = $this->request->post('provider', $this->aiConfig['default_text_provider'] ?? 'qianwen');

        if (empty($prompt)) {
            return json(['code' => 0, 'msg' => '提示词不能为空']);
        }

        try {
            // 确保输入的UTF-8编码正确性
            $prompt = $this->sanitizeUTF8($prompt);

            // 记录请求日志
            $this->writeLog("AI文本生成请求: " . substr($prompt, 0, 100) . "...");

            // 调用AI文本生成服务
            $generatedText = $this->callTextGenerationApi($prompt, $maxTokens, $temperature, $provider);

            if ($generatedText) {
                // 确保输出的UTF-8编码正确性
                $generatedText = $this->sanitizeUTF8($generatedText);

                $this->writeLog("AI文本生成成功，长度: " . mb_strlen($generatedText));
                return json([
                    'code' => 1,
                    'msg' => 'AI文本生成成功',
                    'data' => [
                        'content' => $generatedText,
                        'prompt' => $this->sanitizeUTF8($prompt),
                        'type' => $type,
                        'provider' => $provider,
                        'tokens_used' => mb_strlen($generatedText)
                    ]
                ]);
            } else {
                $this->writeLog("AI文本生成失败：返回内容为空", 'error');
                return json(['code' => 0, 'msg' => 'AI文本生成失败：返回内容为空']);
            }
        } catch (\Exception $e) {
            $this->writeLog("文本生成错误: " . $e->getMessage(), 'error');

            // 如果是账户欠费或API调用失败，返回模拟内容
            if (strpos($e->getMessage(), 'Arrearage') !== false ||
                strpos($e->getMessage(), 'Access denied') !== false ||
                strpos($e->getMessage(), 'API请求失败') !== false) {

                $this->writeLog("API调用失败，使用模拟内容", 'warning');
                $mockContent = $this->generateMockContent($prompt);

                // 确保模拟内容的UTF-8编码正确性
                $mockContent = $this->sanitizeUTF8($mockContent);

                return json([
                    'code' => 1,
                    'msg' => 'AI文本生成成功（模拟模式）',
                    'data' => [
                        'content' => $mockContent,
                        'prompt' => $this->sanitizeUTF8($prompt),
                        'type' => $type,
                        'provider' => $provider . '_mock',
                        'tokens_used' => mb_strlen($mockContent),
                        'note' => 'API调用失败，使用模拟内容'
                    ]
                ]);
            }

            return json(['code' => 0, 'msg' => 'AI文本生成失败: ' . $e->getMessage()]);
        } catch (\Throwable $e) {
            $this->writeLog("文本生成严重错误: " . $e->getMessage(), 'error');
            return json(['code' => 0, 'msg' => 'AI文本生成失败: 系统错误']);
        }
    }

    /**
     * 调用AI文本生成API
     */
    private function callTextGenerationApi($prompt, $maxTokens = 500, $temperature = 0.7, $provider = null)
    {
        $config = $this->aiConfig;
        if (!$provider) {
            $provider = $config['default_provider'] ?? 'qianwen';
        }

        if ($provider === 'qianwen') {
            return $this->callQianwenTextApi($prompt, $maxTokens, $config, $temperature);
        } else {
            throw new Exception('不支持的AI提供商: ' . $provider);
        }
    }

    /**
     * 调用阿里千问文本生成API
     */
    private function callQianwenTextApi($prompt, $maxTokens, $config, $temperature = 0.7)
    {
        $apiKey = $config['qianwen']['api_key'] ?? '';
        $apiUrl = $config['qianwen']['text_api_url'] ?? 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation';

        if (empty($apiKey)) {
            throw new Exception('阿里千问 API密钥未配置');
        }

        $data = [
            'model' => $config['qianwen']['text_model'] ?? 'qwen-turbo',
            'input' => [
                'messages' => [
                    [
                        'role' => 'user',
                        'content' => $prompt
                    ]
                ]
            ],
            'parameters' => [
                'max_tokens' => $maxTokens,
                'temperature' => $temperature
            ]
        ];

        $headers = [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json'
        ];

        $this->writeLog("调用千问API: " . $apiUrl);
        $this->writeLog("请求数据: " . json_encode($data, JSON_UNESCAPED_UNICODE));

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $apiUrl);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        $this->writeLog("API响应状态: " . $httpCode);
        $this->writeLog("API响应内容: " . substr($response, 0, 500) . "...");

        if ($error) {
            throw new Exception('cURL错误: ' . $error);
        }

        if ($httpCode !== 200) {
            throw new Exception('阿里千问 API请求失败，HTTP状态码: ' . $httpCode . '，响应: ' . $response);
        }

        $result = json_decode($response, true);
        if (isset($result['output']['text'])) {
            return trim($result['output']['text']);
        }

        throw new Exception('阿里千问 API返回格式错误: ' . $response);
    }

    /**
     * 测试方法
     */
    public function test()
    {
        try {
            return json([
                'code' => 1,
                'msg' => 'AI控制器工作正常',
                'data' => [
                    'timestamp' => time(),
                    'datetime' => date('Y-m-d H:i:s'),
                    'config_loaded' => is_array($this->aiConfig) && !empty($this->aiConfig),
                    'default_provider' => $this->aiConfig['default_provider'] ?? '未设置',
                    'config_type' => gettype($this->aiConfig),
                    'config_count' => is_array($this->aiConfig) ? count($this->aiConfig) : 0
                ]
            ]);
        } catch (\Exception $e) {
            return json([
                'code' => 0,
                'msg' => '测试失败: ' . $e->getMessage(),
                'data' => null
            ]);
        }
    }

    /**
     * 生成模拟内容
     */
    private function generateMockContent($prompt)
    {
        // 分析提示词中的关键信息
        $title = '';
        $keywords = '';
        $category = '';

        // 提取标题
        if (preg_match('/\*\*文章标题：\*\*\s*(.+?)(?:\n|$)/u', $prompt, $matches)) {
            $title = trim($matches[1]);
        }

        // 提取关键词
        if (preg_match('/\*\*关键词：\*\*\s*(.+?)(?:\n|$)/u', $prompt, $matches)) {
            $keywords = trim($matches[1]);
        }

        // 提取分类
        if (preg_match('/\*\*文章分类：\*\*\s*(.+?)(?:\n|$)/u', $prompt, $matches)) {
            $category = trim($matches[1]);
        }

        // 生成基于提示词的智能内容
        $content = "<div class='ai-generated-content'>\n";

        if ($title) {
            $content .= "<h3>关于「{$title}」</h3>\n";
        }

        $content .= "<h4>引言</h4>\n";
        $content .= "<p>在当今快速发展的时代，";
        if ($keywords) {
            $keywordArray = explode(',', $keywords);
            $content .= implode('、', array_slice($keywordArray, 0, 3));
        } else {
            $content .= "相关主题";
        }
        $content .= "正成为人们关注的焦点。本文将深入探讨这一重要话题，为读者提供全面而深入的分析。</p>\n\n";

        $content .= "<h4>主要内容</h4>\n";
        $content .= "<p>通过深入研究和分析，我们发现：</p>\n";
        $content .= "<ul>\n";
        $content .= "<li>这一领域正在经历前所未有的变革和发展</li>\n";
        $content .= "<li>新技术和新理念不断涌现，为行业带来新的机遇</li>\n";
        $content .= "<li>相关政策和标准也在不断完善，为健康发展提供保障</li>\n";
        $content .= "</ul>\n\n";

        if ($category) {
            $content .= "<p>在{$category}领域，这些变化尤为显著。专家指出，未来几年将是关键的发展期。</p>\n\n";
        }

        $content .= "<h4>深入分析</h4>\n";
        $content .= "<p>从多个维度来看，当前的发展趋势呈现出以下特点：</p>\n";
        $content .= "<p><strong>技术创新：</strong>新技术的应用正在改变传统的工作方式和思维模式。</p>\n";
        $content .= "<p><strong>市场需求：</strong>用户需求的多样化推动了产品和服务的不断优化。</p>\n";
        $content .= "<p><strong>政策支持：</strong>相关政策的出台为行业发展提供了有力支撑。</p>\n\n";

        $content .= "<h4>未来展望</h4>\n";
        $content .= "<p>展望未来，我们有理由相信，随着技术的不断进步和应用的深入，这一领域将迎来更加广阔的发展空间。</p>\n";
        $content .= "<p>同时，我们也需要关注可能面临的挑战，包括技术标准的统一、人才培养的加强、以及可持续发展的实现等。</p>\n\n";

        $content .= "<h4>结论</h4>\n";
        $content .= "<p>综上所述，";
        if ($title) {
            $content .= "「{$title}」";
        } else {
            $content .= "这一主题";
        }
        $content .= "不仅具有重要的现实意义，也为未来的发展指明了方向。我们期待在各方共同努力下，能够取得更大的进步和突破。</p>\n";

        $content .= "</div>\n";

        return $content;
    }

    /**
     * 获取地理位置信息（基于百度地图API）
     */
    public function getLocationInfo()
    {
        if (!$this->request->isPost()) {
            return json(['code' => 0, 'msg' => '请求方式错误']);
        }

        $longitude = $this->request->post('longitude', '');
        $latitude = $this->request->post('latitude', '');

        if (empty($longitude) || empty($latitude)) {
            return json(['code' => 0, 'msg' => '经纬度参数不能为空']);
        }

        try {
            // 调用百度地图API获取周边信息
            $locationData = $this->getBaiduLocationData($longitude, $latitude);

            return json([
                'code' => 1,
                'msg' => '地理位置信息获取成功',
                'data' => $locationData
            ]);
        } catch (\Exception $e) {
            $this->writeLog("获取地理位置信息错误: " . $e->getMessage(), 'error');
            return json(['code' => 0, 'msg' => '获取地理位置信息失败: ' . $e->getMessage()]);
        }
    }

    /**
     * 调用百度地图API获取周边信息
     */
    private function getBaiduLocationData($longitude, $latitude)
    {
        // 百度地图API密钥（需要在配置中设置）
        $baiduApiKey = $this->aiConfig['baidu_map']['api_key'] ?? '';

        if (empty($baiduApiKey)) {
            // 如果没有配置API密钥，返回模拟数据
            return $this->getMockLocationData($longitude, $latitude);
        }

        $locationData = [
            'address' => '',
            'transit' => [],
            'driving' => [],
            'food' => [],
            'life' => []
        ];

        // 1. 逆地理编码 - 获取详细地址
        $address = $this->getBaiduReverseGeocode($longitude, $latitude, $baiduApiKey);
        $locationData['address'] = $address;

        // 2. 周边公交站点查询
        $transitInfo = $this->getBaiduTransitInfo($longitude, $latitude, $baiduApiKey);
        $locationData['transit'] = $transitInfo;

        // 3. 周边美食查询
        $foodInfo = $this->getBaiduPOIInfo($longitude, $latitude, $baiduApiKey, '美食');
        $locationData['food'] = $foodInfo;

        // 4. 周边生活服务查询
        $lifeInfo = $this->getBaiduPOIInfo($longitude, $latitude, $baiduApiKey, '生活服务');
        $locationData['life'] = $lifeInfo;

        // 5. 周边银行查询
        $bankInfo = $this->getBaiduPOIInfo($longitude, $latitude, $baiduApiKey, '银行');
        $locationData['bank'] = $bankInfo;

        // 6. 周边医院查询
        $hospitalInfo = $this->getBaiduPOIInfo($longitude, $latitude, $baiduApiKey, '医院');
        $locationData['hospital'] = $hospitalInfo;

        return $locationData;
    }

    /**
     * 百度地图逆地理编码
     */
    private function getBaiduReverseGeocode($longitude, $latitude, $apiKey)
    {
        $url = "https://api.map.baidu.com/reverse_geocoding/v3/";
        $params = [
            'ak' => $apiKey,
            'output' => 'json',
            'coordtype' => 'wgs84ll',
            'location' => $latitude . ',' . $longitude
        ];

        $response = $this->callBaiduApi($url, $params);

        if ($response && isset($response['result']['formatted_address'])) {
            return $response['result']['formatted_address'];
        }

        return '';
    }

    /**
     * 获取百度地图公交信息
     */
    private function getBaiduTransitInfo($longitude, $latitude, $apiKey)
    {
        $url = "https://api.map.baidu.com/place/v2/search";
        $params = [
            'ak' => $apiKey,
            'output' => 'json',
            'query' => '公交站',
            'page_size' => 10,
            'page_num' => 0,
            'scope' => 1,
            'location' => $latitude . ',' . $longitude,
            'radius' => 1000,
            'coord_type' => 1
        ];

        $response = $this->callBaiduApi($url, $params);
        $transitInfo = [];

        if ($response && isset($response['results'])) {
            foreach ($response['results'] as $item) {
                $transitInfo[] = [
                    'name' => $item['name'] ?? '',
                    'address' => $item['address'] ?? '',
                    'distance' => isset($item['detail_info']['distance']) ? round($item['detail_info']['distance']) . 'm' : ''
                ];
            }
        }

        return array_slice($transitInfo, 0, 5); // 返回最近的5个公交站
    }

    /**
     * 获取百度地图POI信息
     */
    private function getBaiduPOIInfo($longitude, $latitude, $apiKey, $query)
    {
        $url = "https://api.map.baidu.com/place/v2/search";
        $params = [
            'ak' => $apiKey,
            'output' => 'json',
            'query' => $query,
            'page_size' => 10,
            'page_num' => 0,
            'scope' => 1,
            'location' => $latitude . ',' . $longitude,
            'radius' => 1000,
            'coord_type' => 1
        ];

        $response = $this->callBaiduApi($url, $params);
        $poiInfo = [];

        if ($response && isset($response['results'])) {
            foreach ($response['results'] as $item) {
                $poiInfo[] = [
                    'name' => $item['name'] ?? '',
                    'address' => $item['address'] ?? '',
                    'type' => isset($item['detail_info']['tag']) ? $item['detail_info']['tag'] : '',
                    'distance' => isset($item['detail_info']['distance']) ? round($item['detail_info']['distance']) . 'm' : ''
                ];
            }
        }

        return array_slice($poiInfo, 0, 8); // 返回最近的8个POI
    }

    /**
     * 调用百度地图API
     */
    private function callBaiduApi($url, $params)
    {
        $queryString = http_build_query($params);
        $fullUrl = $url . '?' . $queryString;

        $this->writeLog("调用百度地图API: " . $fullUrl);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $fullUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        $this->writeLog("百度地图API响应状态: " . $httpCode);
        $this->writeLog("百度地图API响应内容: " . substr($response, 0, 500) . "...");

        if ($error) {
            throw new \Exception('百度地图API请求错误: ' . $error);
        }

        if ($httpCode !== 200) {
            throw new \Exception('百度地图API请求失败，HTTP状态码: ' . $httpCode);
        }

        $result = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \Exception('百度地图API返回数据格式错误');
        }

        return $result;
    }

    /**
     * 获取模拟地理位置数据（当没有API密钥时使用）
     */
    private function getMockLocationData($longitude, $latitude)
    {
        return [
            'address' => '模拟地址：基于经纬度(' . $longitude . ', ' . $latitude . ')的位置',
            'transit' => [
                ['name' => '模拟公交站A', 'address' => '附近200米', 'distance' => '200m'],
                ['name' => '模拟公交站B', 'address' => '附近350米', 'distance' => '350m'],
                ['name' => '模拟地铁站', 'address' => '附近500米', 'distance' => '500m']
            ],
            'food' => [
                ['name' => '模拟餐厅A', 'type' => '中餐', 'address' => '附近100米', 'distance' => '100m'],
                ['name' => '模拟快餐店', 'type' => '快餐', 'address' => '附近150米', 'distance' => '150m'],
                ['name' => '模拟咖啡厅', 'type' => '咖啡', 'address' => '附近200米', 'distance' => '200m']
            ],
            'life' => [
                ['name' => '模拟超市', 'type' => '购物', 'address' => '附近300米', 'distance' => '300m'],
                ['name' => '模拟药店', 'type' => '医疗', 'address' => '附近250米', 'distance' => '250m']
            ],
            'bank' => [
                ['name' => '模拟银行A', 'type' => '银行', 'address' => '附近400米', 'distance' => '400m']
            ],
            'hospital' => [
                ['name' => '模拟诊所', 'type' => '医疗', 'address' => '附近600米', 'distance' => '600m']
            ]
        ];
    }

    /**
     * 获取教学点课程信息
     */
    public function getOcationCourses()
    {
        if (!$this->request->isPost()) {
            return json(['code' => 0, 'msg' => '请求方式错误']);
        }

        $ocationId = $this->request->post('ocation_id', '');

        if (empty($ocationId)) {
            return json(['code' => 0, 'msg' => '教学点ID不能为空']);
        }

        try {
            // 获取教学点课程信息
            $coursesData = $this->getOcationCoursesData($ocationId);

            return json([
                'code' => 1,
                'msg' => '课程信息获取成功',
                'data' => $coursesData
            ]);
        } catch (\Exception $e) {
            $this->writeLog("获取教学点课程信息错误: " . $e->getMessage(), 'error');
            return json(['code' => 0, 'msg' => '获取课程信息失败: ' . $e->getMessage()]);
        }
    }

    /**
     * 获取教学点课程数据
     */
    private function getOcationCoursesData($ocationId)
    {
        $coursesData = [
            'ocation_id' => $ocationId,
            'courses' => [],
            'total_count' => 0,
            'active_count' => 0,
            'course_categories' => [],
            'table_info' => '',
            'search_scope' => '当前教学点'
        ];

        try {
            $this->writeLog("开始查询教学点课程信息，教学点ID: {$ocationId}");

            // 获取该教学点及其所有子教学点的ID
            $ocationIds = $this->getAllSubOcationIds($ocationId);
            $searchOcationIds = $ocationIds;

            // 使用course_table_autoplan_temp表查询课程数据
            $courses = $this->queryCourseTableDirect($ocationIds);

            if (empty($courses)) {
                $this->writeLog("当前教学点及子教学点无课程数据");
                $coursesData['search_scope'] = '当前教学点 + ' . (count($ocationIds) - 1) . '个子教学点';
            } else {
                $coursesData['search_scope'] = '当前教学点 + ' . (count($ocationIds) - 1) . '个子教学点';
                $this->writeLog("查询到 " . count($courses) . " 条课程记录");
            }

            $coursesData['table_info'] = "使用course_table_autoplan_temp表";
            $coursesData['searched_ocation_ids'] = $searchOcationIds;

            foreach ($courseTableNames as $tableName) {
                try {
                    $this->writeLog("尝试查询表: {$tableName}");

                    // 先检查表是否存在
                    $tableExists = \think\Db::query("SHOW TABLES LIKE '{$tableName}'");
                    if (empty($tableExists)) {
                        $this->writeLog("表 {$tableName} 不存在");
                        continue;
                    }

                    // 检查表结构，看是否有ocation_id字段
                    $columns = \think\Db::query("SHOW COLUMNS FROM {$tableName}");
                    $hasOcationId = false;
                    $availableFields = [];

                    foreach ($columns as $column) {
                        $availableFields[] = $column['Field'];
                        if ($column['Field'] === 'ocation_id') {
                            $hasOcationId = true;
                        }
                    }

                    $this->writeLog("表 {$tableName} 字段: " . implode(', ', $availableFields));

                    if (!$hasOcationId) {
                        $this->writeLog("表 {$tableName} 没有 ocation_id 字段");
                        continue;
                    }

                    // 构建查询字段，只选择存在的字段
                    $selectFields = ['id', 'ocation_id']; // 添加ocation_id字段用于标识来源
                    $possibleFields = ['name', 'title', 'content', 'intro', 'description', 'summary', 'detail', 'category_id', 'teacher_id', 'start_time', 'end_time', 'create_time', 'createtime', 'update_time', 'updatetime', 'status'];

                    foreach ($possibleFields as $field) {
                        if (in_array($field, $availableFields)) {
                            $selectFields[] = $field;
                        }
                    }

                    $this->writeLog("查询字段: " . implode(', ', $selectFields));

                    // 第一步：查询当前教学点的课程
                    $query = \think\Db::name($tableName)
                        ->where('ocation_id', $ocationId)
                        ->field(implode(', ', $selectFields));

                    // 如果有status字段，只查询有效课程
                    if (in_array('status', $availableFields)) {
                        $query->where('status', 1);
                    }

                    // 排序
                    if (in_array('create_time', $availableFields)) {
                        $query->order('create_time DESC, id DESC');
                    } elseif (in_array('createtime', $availableFields)) {
                        $query->order('createtime DESC, id DESC');
                    } else {
                        $query->order('id DESC');
                    }

                    $courses = $query->select();
                    $usedTable = $tableName;
                    $this->writeLog("从当前教学点查询到 " . count($courses) . " 条课程记录");

                    // 如果当前教学点没有课程，查询子教学点的课程
                    if (empty($courses)) {
                        $this->writeLog("当前教学点无课程，开始查询子教学点");
                        $childOcationIds = $this->getChildOcationIds($ocationId);

                        if (!empty($childOcationIds)) {
                            $this->writeLog("找到子教学点: " . implode(', ', $childOcationIds));
                            $searchOcationIds = array_merge($searchOcationIds, $childOcationIds);
                            $coursesData['search_scope'] = '当前教学点 + ' . count($childOcationIds) . '个子教学点';

                            // 查询所有子教学点的课程
                            $childQuery = \think\Db::name($tableName)
                                ->whereIn('ocation_id', $childOcationIds)
                                ->field(implode(', ', $selectFields));

                            if (in_array('status', $availableFields)) {
                                $childQuery->where('status', 1);
                            }

                            if (in_array('create_time', $availableFields)) {
                                $childQuery->order('create_time DESC, id DESC');
                            } elseif (in_array('createtime', $availableFields)) {
                                $childQuery->order('createtime DESC, id DESC');
                            } else {
                                $childQuery->order('id DESC');
                            }

                            $childCourses = $childQuery->select();
                            $courses = $childCourses;
                            $this->writeLog("从子教学点查询到 " . count($childCourses) . " 条课程记录");
                        } else {
                            $this->writeLog("未找到子教学点");
                        }
                    }

                    break;

                } catch (\Exception $e) {
                    $this->writeLog("查询表 {$tableName} 失败: " . $e->getMessage());
                    continue;
                }
            }

            $coursesData['table_info'] = $usedTable ? "使用表: {$usedTable}" : "未找到合适的课程表";
            $coursesData['searched_ocation_ids'] = $searchOcationIds;

            if ($courses && count($courses) > 0) {
                foreach ($courses as $course) {
                    // 获取课程名称
                    $courseName = $course['className'] ?? $course['course_name'] ?? $course['classes_name'] ?? '未命名课程';

                    // 获取课程内容（优先级：detail_description > description > intro）
                    $courseContent = '';
                    if (!empty($course['detail_description'])) {
                        $courseContent = $this->sanitizeUTF8($course['detail_description']);
                    } elseif (!empty($course['description'])) {
                        $courseContent = $this->sanitizeUTF8($course['description']);
                    } elseif (!empty($course['intro'])) {
                        $courseContent = $this->sanitizeUTF8($course['intro']);
                    }

                    // 获取课程简介
                    $courseIntro = $this->sanitizeUTF8($course['description'] ?? $course['intro'] ?? '');

                    $courseInfo = [
                        'id' => $course['t_id'] ?? $course['id'],
                        'name' => $this->sanitizeUTF8($courseName),
                        'content' => $courseContent, // 完整的课程内容（已处理UTF-8）
                        'intro' => $courseIntro, // 课程简介（已处理UTF-8）
                        'description' => $this->sanitizeUTF8($course['description'] ?? ''),
                        'category_id' => $course['subject_id'] ?? 0,
                        'category_name' => $this->sanitizeUTF8($course['subject'] ?? $course['subject_name'] ?? ''),
                        'teacher_id' => 0,
                        'teacher_name' => '',
                        'start_time' => $course['start_date'] ?? '',
                        'end_time' => $course['end_date'] ?? '',
                        'create_time' => '',
                        'update_time' => '',
                        'status' => 1,
                        'duration_desc' => '',
                        'is_long_term' => false,
                        'source_ocation_id' => $course['ocation_id'] ?? $ocationId,
                        'source_ocation_name' => $this->sanitizeUTF8($course['ocation_name'] ?? ''),
                        'is_from_child' => ($course['ocation_id'] ?? $ocationId) != $ocationId,
                        'has_content' => !empty($courseContent), // 标识是否有内容
                        'content_length' => mb_strlen($courseContent), // 内容长度
                        'content_preview' => mb_substr($courseContent, 0, 100), // 内容预览（前100字符）
                        'price' => $course['price'] ?? 0,
                        'is_free' => ($course['price'] ?? 0) == 0,
                        'cover_image' => $this->sanitizeUTF8($course['cover'] ?? ''),
                        'address' => $this->sanitizeUTF8($course['address'] ?? ''),
                        'school_name' => $this->sanitizeUTF8($course['schoolName'] ?? ''),
                        'classes_type' => $course['classes_type'] ?? 0,
                        'table_type' => $course['table_type'] ?? 0
                    ];

                    // 获取课程分类名称
                    if ($courseInfo['category_id']) {
                        try {
                            $category = \think\Db::name('category')
                                ->where('id', $courseInfo['category_id'])
                                ->field('name')
                                ->find();
                            if ($category) {
                                $courseInfo['category_name'] = $category['name'];
                            }
                        } catch (\Exception $e) {
                            $this->writeLog("获取分类信息失败: " . $e->getMessage());
                        }
                    }

                    // 获取教师名称
                    if ($courseInfo['teacher_id']) {
                        try {
                            $teacher = \think\Db::name('teacher')
                                ->where('id', $courseInfo['teacher_id'])
                                ->field('name')
                                ->find();
                            if ($teacher) {
                                $courseInfo['teacher_name'] = $teacher['name'];
                            }
                        } catch (\Exception $e) {
                            $this->writeLog("获取教师信息失败: " . $e->getMessage());
                        }
                    }

                    // 判断课程时长和类型
                    if ($courseInfo['start_time'] && $courseInfo['end_time']) {
                        $startTime = strtotime($courseInfo['start_time']);
                        $endTime = strtotime($courseInfo['end_time']);

                        if ($startTime && $endTime) {
                            $duration = $endTime - $startTime;

                            if ($duration > 365 * 24 * 3600) { // 超过一年
                                $courseInfo['duration_desc'] = '常年开设';
                                $courseInfo['is_long_term'] = true;
                            } elseif ($duration > 90 * 24 * 3600) { // 超过3个月
                                $courseInfo['duration_desc'] = '长期课程';
                            } elseif ($duration > 30 * 24 * 3600) { // 超过1个月
                                $courseInfo['duration_desc'] = '中期课程';
                            } else {
                                $courseInfo['duration_desc'] = '短期课程';
                            }
                        } else {
                            $courseInfo['duration_desc'] = '时间待定';
                        }
                    } else {
                        $courseInfo['duration_desc'] = '时间待定';
                    }

                    $coursesData['courses'][] = $courseInfo;

                    // 统计分类
                    if ($courseInfo['category_name']) {
                        if (!in_array($courseInfo['category_name'], $coursesData['course_categories'])) {
                            $coursesData['course_categories'][] = $courseInfo['category_name'];
                        }
                    }
                }

                $coursesData['total_count'] = count($courses);
                $coursesData['active_count'] = count(array_filter($courses, function($course) {
                    return ($course['status'] ?? 1) == 1;
                }));
            }

            $this->writeLog("获取教学点课程信息完成，教学点ID: {$ocationId}，课程数量: " . $coursesData['total_count']);

        } catch (\Exception $e) {
            $this->writeLog("查询教学点课程信息失败: " . $e->getMessage(), 'error');
            $coursesData['table_info'] = "查询失败: " . $e->getMessage();
        }

        // 确保返回数据的UTF-8编码正确性
        $coursesData = $this->safeJsonEncode($coursesData);

        return $coursesData;
    }

    /**
     * 通过API获取教学点课程数据
     */
    private function getCoursesFromAPI($ocationId)
    {
        $courses = [];

        try {
            $this->writeLog("调用API获取教学点课程，教学点ID: {$ocationId}");

            // 获取该教学点及其所有子教学点的ID
            $ocationIds = $this->getAllSubOcationIds($ocationId);

            // 调用baseCourseQuery方法获取课程数据
            $params = [
                'page' => 1,
                'limit' => 50, // 获取更多课程用于AI分析
                'ocation_ids' => $ocationIds,
                'include_sub_ocations' => true,
                'order' => 'start_time desc' // 按开始时间倒序排列
            ];

            // 直接查询course_table_autoplan_temp表
            $courseData = $this->queryCourseTableDirect($ocationIds);

            if (!empty($courseData)) {
                foreach ($courseData as $course) {
                    $courseInfo = [
                        'id' => $course['t_id'] ?? $course['id'],
                        'name' => $course['className'] ?? $course['course_name'] ?? $course['classes_name'] ?? '未命名课程',
                        'content' => $course['detail_description'] ?? $course['description'] ?? '',
                        'intro' => $course['description'] ?? $course['intro'] ?? '',
                        'description' => $course['description'] ?? '',
                        'category_id' => $course['subject_id'] ?? 0,
                        'category_name' => $course['subject'] ?? $course['subject_name'] ?? '',
                        'teacher_id' => 0,
                        'teacher_name' => '',
                        'start_time' => $course['start_date'] ?? '',
                        'end_time' => $course['end_date'] ?? '',
                        'create_time' => '',
                        'update_time' => '',
                        'status' => 1,
                        'duration_desc' => '',
                        'is_long_term' => false,
                        'source_ocation_id' => $course['ocation_id'] ?? $ocationId,
                        'source_ocation_name' => $course['ocation_name'] ?? '',
                        'is_from_child' => ($course['ocation_id'] ?? $ocationId) != $ocationId,
                        'has_content' => !empty($course['detail_description'] ?? $course['description'] ?? ''),
                        'content_length' => mb_strlen($course['detail_description'] ?? $course['description'] ?? ''),
                        'content_preview' => mb_substr($course['detail_description'] ?? $course['description'] ?? '', 0, 100),
                        'price' => $course['price'] ?? 0,
                        'is_free' => ($course['price'] ?? 0) == 0,
                        'cover_image' => $course['cover'] ?? '',
                        'address' => $course['address'] ?? ''
                    ];

                    // 判断课程时长和类型
                    if ($courseInfo['start_time'] && $courseInfo['end_time']) {
                        $startTime = strtotime($courseInfo['start_time']);
                        $endTime = strtotime($courseInfo['end_time']);

                        if ($startTime && $endTime) {
                            $duration = $endTime - $startTime;

                            if ($duration > 365 * 24 * 3600) { // 超过一年
                                $courseInfo['duration_desc'] = '常年开设';
                                $courseInfo['is_long_term'] = true;
                            } elseif ($duration > 90 * 24 * 3600) { // 超过3个月
                                $courseInfo['duration_desc'] = '长期课程';
                            } elseif ($duration > 30 * 24 * 3600) { // 超过1个月
                                $courseInfo['duration_desc'] = '中期课程';
                            } else {
                                $courseInfo['duration_desc'] = '短期课程';
                            }
                        } else {
                            $courseInfo['duration_desc'] = '时间待定';
                        }
                    } else {
                        $courseInfo['duration_desc'] = '时间待定';
                    }

                    $courses[] = $courseInfo;
                }

                $this->writeLog("API获取到 " . count($courses) . " 条课程记录");
            } else {
                $this->writeLog("API未获取到课程数据");
            }

        } catch (\Exception $e) {
            $this->writeLog("API获取课程数据失败: " . $e->getMessage(), 'error');
        }

        return $courses;
    }

    /**
     * 直接查询课程表获取数据
     */
    private function queryCourseTableDirect($ocationIds)
    {
        try {
            if (empty($ocationIds)) {
                return [];
            }

            // 确保ocationIds是数组
            if (!is_array($ocationIds)) {
                $ocationIds = [$ocationIds];
            }

            $this->writeLog("直接查询课程表，教学点IDs: " . implode(', ', $ocationIds));

            $query = \think\Db::name('course_table_autoplan_temp')
                ->alias('t')
                ->join('eb_school sch', 'sch.id=t.school_id', 'LEFT')
                ->join('eb_classes c1', 'c1.id=t.classes_id', 'LEFT')
                ->join('fa_community_code_config c2', 't.table_type=2 AND c2.id=t.classes_id', 'LEFT')
                ->join('fa_community_course_config course2', 't.table_type=2 AND course2.id=t.subject_lv', 'LEFT')
                ->join('fa_course_table tb', 't.table_type=1 AND tb.id=t.table_id', 'left')
                ->join('fa_community_publicwelfare tb2', 't.table_type=2 AND tb2.id=t.publicwelfare_id', 'left')
                ->join('fa_ocation o', 'o.id=t.ocation_id', 'INNER')
                ->join('fa_ocation o2', 'o.pid=o2.id', 'LEFT')
                ->join('fa_address_lv s', 't.table_type=1 AND s.id=c1.addresslv_id', 'LEFT')
                ->join('fa_subject_lv sb', 't.table_type=1 AND sb.id=c1.subject_lv', 'LEFT')
                ->field("t.id as t_id,
                        t.school_id,
                        sch.name as schoolName,
                        t.classes_id as class_id,
                        COALESCE(c1.name, CONCAT(o.name,course2.name,'课堂')) as className,
                        COALESCE(c1.subject_lv, t.subject_lv) as subject_id,
                        o.rel_type,
                        o.address_lv_octionlevel,
                        c1.classes_type,
                        COALESCE(tb.start_date, CONCAT(t.date,' ', t.start_time)) as start_date,
                        COALESCE(tb.end_date, CONCAT(t.date,' ', t.end_time)) as end_date,
                        o.id as ocation_id,
                        CONCAT(COALESCE(o2.name, ''), o.name) as ocation_name,
                        COALESCE(c1.cover, course2.cover) as cover,
                        COALESCE(sb.name, course2.name) as subject,
                        COALESCE(c1.price, 0) as price,
                        t.table_id,
                        t.table_type,
                        tb.name as course_name,
                        c1.intro as description,
                        c1.description as detail_description,
                        o.address as address,
                        c1.name as classes_name,
                        sb.name as subject_name")
                ->whereIn('t.ocation_id', $ocationIds)
                ->where('t.status', 1)
                ->order('t.date DESC, t.start_time DESC')
                ->group("t.ocation_id,t.classes_id")
                ->limit(50)
                ->select();

            $result = $query ? $query->toArray() : [];
            $this->writeLog("直接查询获取到 " . count($result) . " 条记录");

            return $result;

        } catch (\Exception $e) {
            $this->writeLog("直接查询课程表失败: " . $e->getMessage(), 'error');
            return [];
        }
    }

    /**
     * 获取所有子教学点ID（兼容Event控制器的方法）
     */
    private function getAllSubOcationIds($ocationId)
    {
        $allIds = [$ocationId];

        try {
            $childIds = $this->getChildOcationIds($ocationId);
            if (!empty($childIds)) {
                $allIds = array_merge($allIds, $childIds);
            }
        } catch (\Exception $e) {
            $this->writeLog("获取子教学点ID失败: " . $e->getMessage(), 'error');
        }

        return array_unique($allIds);
    }

    /**
     * 获取子教学点ID列表
     */
    private function getChildOcationIds($parentOcationId)
    {
        $childIds = [];

        try {
            // 尝试不同的教学点表名
            $ocationTableNames = ['ocation', 'eb_ocation', 'fa_ocation'];

            foreach ($ocationTableNames as $tableName) {
                try {
                    // 检查表是否存在
                    $tableExists = \think\Db::query("SHOW TABLES LIKE '{$tableName}'");
                    if (empty($tableExists)) {
                        continue;
                    }

                    // 检查表结构
                    $columns = \think\Db::query("SHOW COLUMNS FROM {$tableName}");
                    $hasPidField = false;
                    $hasStatusField = false;

                    foreach ($columns as $column) {
                        if ($column['Field'] === 'pid') {
                            $hasPidField = true;
                        }
                        if ($column['Field'] === 'status') {
                            $hasStatusField = true;
                        }
                    }

                    if (!$hasPidField) {
                        $this->writeLog("表 {$tableName} 没有 pid 字段");
                        continue;
                    }

                    // 递归查询所有子教学点
                    $childIds = $this->getChildOcationIdsRecursive($tableName, $parentOcationId, $hasStatusField);

                    if (!empty($childIds)) {
                        $this->writeLog("从表 {$tableName} 找到子教学点: " . implode(', ', $childIds));
                        break;
                    }

                } catch (\Exception $e) {
                    $this->writeLog("查询表 {$tableName} 的子教学点失败: " . $e->getMessage());
                    continue;
                }
            }

        } catch (\Exception $e) {
            $this->writeLog("获取子教学点ID失败: " . $e->getMessage(), 'error');
        }

        return $childIds;
    }

    /**
     * 递归获取所有子教学点ID
     */
    private function getChildOcationIdsRecursive($tableName, $parentId, $hasStatusField = true)
    {
        $allChildIds = [];

        try {
            // 查询直接子教学点
            $query = \think\Db::name($tableName)
                ->where('pid', $parentId)
                ->field('id');

            // 如果有status字段，只查询有效的教学点
            if ($hasStatusField) {
                $query->where('status', 1);
            }

            $directChildren = $query->select();

            foreach ($directChildren as $child) {
                $childId = $child['id'];
                $allChildIds[] = $childId;

                // 递归查询子教学点的子教学点
                $grandChildren = $this->getChildOcationIdsRecursive($tableName, $childId, $hasStatusField);
                $allChildIds = array_merge($allChildIds, $grandChildren);
            }

        } catch (\Exception $e) {
            $this->writeLog("递归查询子教学点失败: " . $e->getMessage(), 'error');
        }

        return array_unique($allChildIds);
    }

    /**
     * 清理和修复UTF-8编码
     */
    private function sanitizeUTF8($text)
    {
        if (empty($text)) {
            return $text;
        }

        // 检查是否为有效的UTF-8
        if (!mb_check_encoding($text, 'UTF-8')) {
            // 尝试从其他编码转换
            $text = mb_convert_encoding($text, 'UTF-8', 'auto');
        }

        // 移除或替换无效的UTF-8字符
        $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');

        // 移除控制字符（除了换行、回车、制表符）
        $text = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $text);

        // 移除BOM标记
        $text = str_replace("\xEF\xBB\xBF", '', $text);

        // 确保字符串以UTF-8编码结束
        return trim($text);
    }

    /**
     * 安全的JSON编码，处理UTF-8问题
     */
    private function safeJsonEncode($data)
    {
        // 递归处理数组和对象中的字符串
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                $data[$key] = $this->safeJsonEncode($value);
            }
        } elseif (is_object($data)) {
            foreach ($data as $key => $value) {
                $data->$key = $this->safeJsonEncode($value);
            }
        } elseif (is_string($data)) {
            $data = $this->sanitizeUTF8($data);
        }

        return $data;
    }

    /**
     * 简单测试方法
     */
    public function simpleTest()
    {
        return json([
            'code' => 1,
            'msg' => '简单测试成功',
            'data' => [
                'time' => date('Y-m-d H:i:s'),
                'utf8_test' => $this->sanitizeUTF8('测试UTF-8编码：中文字符')
            ]
        ]);
    }
}
